<?php
namespace Service;

class Permission extends Base
{

    public function getDatabase()
    {
        return $this->get(DATABASE_PERMISSION);
    }

    public function getPermissionFromCode()
    {
        $list = [];
        $codeDir = APPLICATION_PATH . '/' . ADMIN_MODULE . '/Controller';
        $fileList = readFileFromDir($codeDir);
        foreach($fileList as $file){
            if(isPhpFile($file)){
                $content = file_get_contents($file);
                $data = getClassAndMethodFromCode($content);
                $temp = parseMethod($data['method']);
                if(empty($temp['all'])){
                    continue;
                }
                $list[$data['class']] = [
                    'class' => $data['class'],
                    'method' => $temp
                ];
            }
        }
        return $list;
    }

    public function getPermissionFromModel()
    {
        $list = [];
        $serviceModel = $this->get(SERVICE_MODEL);
        $models = $serviceModel->getIndex(1, 10000);
        foreach($models['list'] as $model){
            $list[$model->dry_controller_name] = [
                'class' => $model->dry_controller_name,
                'method' => parseMethod(['indexAction', 'showAction', 'newAction', 'editAction', 'deleteAction'])
            ];
        }
        return $list;
    }

    public function getPermission()
    {
        $list = [];
        $list1 = $this->getPermissionFromCode();
        $list2 = $this->getPermissionFromModel();
        $keys1 = array_keys($list1);
        $keys2 = array_keys($list2);
        $keys = array_merge($keys1, $keys2);
        foreach($keys as $key){
            if(isset($list1[$key]) && isset($list2[$key])){
                $item1 = $list1[$key];
                $item2 = $list2[$key];
                $item = $item1;
                $item['method']['all'] = array_merge($item1['method']['all'], $item2['method']['all']);
                $item['method']['common'] = array_merge($item1['method']['common'], $item2['method']['common']);
                $item['method']['extension'] = array_merge($item1['method']['extension'], $item2['method']['extension']);
                $list[$key] = $item;
            }
            else if(isset($list1[$key])){
                $list[$key] = $list1[$key];
            }
            else{
                $list[$key] = $list2[$key];
            }
        }
        return $list;
    }

    public function getPermissionWithLanguage()
    {
        $result = [];
        $commonIn = ['index', 'show', 'new', 'edit', 'delete'];
        $list = $this->getPermission();
        $applicationConfig = $this->getInstance('applicationConfig');
        foreach($list as $item){
            $class = $item['class'];
            if(in_array($class, $applicationConfig['admin']['controller_white_list'])){
                continue;
            }
            $common = $item['method']['common'];
            $extension = $item['method']['extension'];
            $commonPermission = [];
            $extensionPermission = [];
            /**/
            foreach($commonIn as $name){
                if(in_array($name, $common)){
                    $commonPermission[$name] = [
                        'show' => true,
                        'permission' => "/*/{$class}/{$name}",
                        'horizontal_group' => $class,
                        'vertical_group' => $name,
                        'text' => $this->language($name)
                    ];
                }
                else{
                    $commonPermission[$name] = ['show' => false];
                }
            }
            /**/
            foreach($extension as $name){
                $extensionPermission[] = [
                    'permission' => "/*/{$class}/{$name}",
                    'extension_group' => $class,
                    'text' => $this->language('Extension' . $class . ucfirst($name))
                ];
            }
            /**/
            $result[] = [
                'model' => $class,
                'text' => $this->language($class),
                'common' => $commonPermission,
                'extension' => $extensionPermission
            ];
        }
        return $result;
    }

    public function language($name)
    {
        return $this->get(SERVICE_DRY)->language($name);
    }

    public function getSignPass()
    {
        $list = getConfig('signPass', THE_DEFAULT);
        return $list;
    }

    public function check($request, $data, $groupId, $token)
    {
        $referer = '';
        if(isset($request->header['referer'])){
            $referer = $request->header['referer'];
        }
        list($module, $controller, $action) = parseUrl($request->server['request_uri']);
        if($module == 'Admin'){
            return $this->checkAdmin($request, $referer, $data, $groupId, $token, $module, $controller, $action);
        }
        else if($module == 'Api'){
            return $this->checkApi($request, $referer, $data, $groupId, $token, $module, $controller, $action);
        }
    }

    public function checkAdmin($request, $referer, $data, $groupId, $token, $module, $controller, $action)
    {
        $device = 'admin';
        $route = "/{$module}/{$controller}/{$action}";
        $serviceDry = $this->get(SERVICE_DRY);
        /*如果在黑名单里面(先检查黑名单)*/
        $blackList = $serviceDry->getPermissionBlackList();
        $blackList = array2arrayByKey($blackList, 'dry_name');
        if(in_array($route, $blackList)){
            return false;
        }
        /*如果在白名单里面*/
        $whiteList = $serviceDry->getPermissionWhiteList();
        $whiteList = array2arrayByKey($whiteList, 'dry_name');
        if(in_array($route, $whiteList)){
            return true;
        }
        /**/
        $bool = require(SRC_PATH . '/Php/checkPermission1.php');
        if(is_bool($bool)){
            return $bool;
        }
        /*如果在黑名单里面(针对用户的)(先检查黑名单)*/
        $blackList = $serviceDry->getPermissionBlackList($user->dry_username);
        $blackList = array2arrayByKey($blackList, 'dry_name');
        if(in_array($route, $blackList)){
            return false;
        }
        /*如果在白名单里面(针对用户的)*/
        $whiteList = $serviceDry->getPermissionWhiteList($user->dry_username);
        $whiteList = array2arrayByKey($whiteList, 'dry_name');
        if(in_array($route, $whiteList)){
            return true;
        }
        /**/
        $bool = require(SRC_PATH . '/Php/checkPermission2.php');
        if(is_bool($bool)){
            return $bool;
        }
        return false;
    }

    public function checkApi($request, $referer, $data, $groupId, $token, $module, $controller, $action)
    {
        $route = "/{$module}/{$controller}/{$action}";
        /*如果不需要签名*/
        $signPassList = $this->getSignPass();
        if(in_array($route, $signPassList)){
            return true;
        }
        /*同一个域名请求的验证权限*/
        if($this->isSameDomain($referer)){
            $device = 'admin';
            $bool = require(SRC_PATH . '/Php/checkPermission1.php');
            if(is_bool($bool)){
                return $bool;
            }
            $bool = require(SRC_PATH . '/Php/checkPermission2.php');
            if(is_bool($bool)){
                return $bool;
            }
        }
        /*不是同一个域名请求的验证签名*/
        else{
            $serviceSign = $this->get(SERVICE_SIGN);
            if(!isset($data['sign']) || empty($data['sign']) || !$serviceSign->checkSign($data)){
                return false;
            }
        }
        return true;
    }

    private function isSameDomain($referer)
    {
        if(empty($referer)){
            return false;
        }
        $info = parse_url($referer);
        $data = $info['host'];
        if(isset($info['port'])){
            $data = "{$info['host']}:{$info['port']}";
        }
        $httpOrHttps = [
            "http://{$data}",
            "https://{$data}"
        ];
        $domain = getDomain();
        if(in_array($domain, $httpOrHttps)){
            return true;
        }
        return false;
    }

    public function filterMenu($list, $groupId, $token)
    {
        $device = 'admin';
        $empty = [];
        if($groupId <= 0){
            return $empty;
        }
        if(!$token){
            return $empty;
        }
        $serviceUser = $this->get(SERVICE_USER);
        $result = $serviceUser->validToken($device, $token);
        if(!$result){
            return $empty;
        }
        $userId = $result['id'];
        /*用户组是不是所属token的用户*/
        $user = $serviceUser->one($userId);
        $groupIn = explode(',', $user->dry_group);
        if(!in_array($groupId, $groupIn)){
            return $empty;
        }
        /*如果是超管*/
        $group = $this->get(SERVICE_GROUP)->one($groupId);
        if($group->dry_alias == 'GROUP_SUPER_ADMIN'){
            return $list;
        }
        /*白名单和黑名单*/
        $serviceDry = $this->get(SERVICE_DRY);
        $whiteList1 = $serviceDry->getPermissionWhiteList();
        $whiteList1 = array2arrayByKey($whiteList1, 'dry_name');
        $whiteList2 = $serviceDry->getPermissionWhiteList($user->dry_username);
        $whiteList2 = array2arrayByKey($whiteList2, 'dry_name');
        $whiteList = array_merge($whiteList1, $whiteList2);
        $blackList1 = $serviceDry->getPermissionBlackList();
        $blackList1 = array2arrayByKey($blackList1, 'dry_name');
        $blackList2 = $serviceDry->getPermissionBlackList($user->dry_username);
        $blackList2 = array2arrayByKey($blackList2, 'dry_name');
        $blackList = array_merge($blackList1, $blackList2);
        /*用户组的权限*/
        $tempList = $this->get(SERVICE_GROUPPERMISSION)->getMoreByGroup($groupId);
        $groupPermissionList = [];
        foreach($tempList as $v){
            $groupPermissionList[] = str_replace('*', 'Admin', $v->dry_route_name);
        }
        $whiteList = array_merge($whiteList, $groupPermissionList);
        /*别名的控制器名称*/
        $tempList = $this->get(SERVICE_MODEL)->getAliasControllerName();
        $map = array2mapObject($tempList, 'dry_alias');
        /**/
        $resultList = [];
        foreach($list as $menu){
            $result = $this->filterMenuInner($menu, $whiteList, $blackList, $map);
            if($result['save'] && !$result['delete']){
                $resultList[] = $menu;
            }
        }
        /*没有子节点的删除*/
        $info = [];
        foreach($resultList as $menu){
            $info[$menu->dry_parent][] = $menu->id;
        }
        $returnList = [];
        foreach($resultList as $menu){
            $bool1 = $menu->dry_grade > 1;
            $bool2 = (isset($info[$menu->id]) && !empty($info[$menu->id]));
            if($bool1 || $bool2){
                $returnList[] = $menu;
            }
        }
        return $returnList;
    }

    private function filterMenuInner($menu, $whiteList, $blackList, $map)
    {
        $default = [
            'save' => false,
            'delete' => true
        ];
        $r = $menu->dry_link;
        $url = parse_url($r);
        $data = explode('/', $url['path']);
        $query = [];
        if(isset($url['query'])){
            parse_str($url['query'], $query);
        }
        if(count($data) == 4 && $data[2] == 'Automate' && isset($query['alias']) && isset($map[$query['alias']])){
            $data[2] = $map[$query['alias']]->dry_controller_name;
            $r = implode('/', $data);
        }
        $bool1 = empty($r);
        $bool2 = (in_array($r, $whiteList) && !in_array($r, $blackList));
        if($bool1 || $bool2){
            return [
                'save' => true,
                'delete' => false
            ];
        }
        return $default;
    }

}